package org.dev.vlp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.startup.UserConfig;
import org.dev.vlp.config.mail.BaseMailConfig;
import org.dev.vlp.config.mail.VerifyMailConfig;
import org.dev.vlp.constants.CachePrefix;
import org.dev.vlp.constants.MailEnum;
import org.dev.vlp.constants.Roles;
import org.dev.vlp.dto.EditPasswordParam;
import org.dev.vlp.dto.EditUserParam;
import org.dev.vlp.dto.UserLoginParam;
import org.dev.vlp.entity.User;
import org.dev.vlp.exception.ApiException;
import org.dev.vlp.service.StatisticsService;
import org.dev.vlp.service.UserService;
import org.dev.vlp.mapper.UserMapper;
import org.dev.vlp.utils.BeanCopyUtils;
import org.dev.vlp.utils.MD5Utils;
import org.dev.vlp.utils.MailUtils;
import org.dev.vlp.utils.TokenUtils;
import org.dev.vlp.vo.LoginVo;
import org.dev.vlp.vo.UserInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.mail.internet.MimeMessage;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
* @author 86184
* @description 针对表【vlp_user】的数据库操作Service实现
* @createDate 2023-01-03 13:41:08
*/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Autowired
    private VerifyMailConfig verifyMailConfig;

    @Autowired
    private MailUtils mailUtils;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StatisticsService statisticsService;

    @Autowired
    TokenUtils tokenUtils;

    String genMailCodeKey(String plain, BaseMailConfig mailConfig) {
        String plainText = CachePrefix.VERIFICATION_CODE_PREFIX + plain + mailConfig.getSubject();
        return DigestUtils.md5DigestAsHex(plainText.getBytes(StandardCharsets.UTF_8));
    }

    @Override
    public void verificationCodeMail(String mailTo) {
        String code = mailUtils.getVerificationCode();
        String codeKey=genMailCodeKey(mailTo,verifyMailConfig);
        Boolean repeatSend = checkRepeatSend(codeKey, verifyMailConfig);
        // 未到重发时限，拒绝发送
        if (!repeatSend) {
            log.info("repeatSend:" + repeatSend);
            throw new ApiException("未到重发时限");
        }
        String s = mailUtils.sendVerificationCode(mailTo, verifyMailConfig, code);
        redisTemplate.opsForValue().set(codeKey, code, verifyMailConfig.getTimeout(), TimeUnit.SECONDS);

    }

    @Override
    public void register(UserLoginParam user) {
        if (user.getEmail() == null || user.getPassword() == null || user.getEmail().equals("") || user.getPassword().equals("")) {
            throw new ApiException("邮箱或密码不能为空");
        }
        String codeKey=genMailCodeKey(user.getEmail(),verifyMailConfig);
        String code = (String) redisTemplate.opsForValue().get(codeKey);
        if(!code.equals(user.getCode())){
            throw new ApiException("验证码错误");
        }
        // 先验证数据库中是否有该邮箱
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("email", user.getEmail());
        Long c = userMapper.selectCount(wrapper);
        if (c != 0) {
            throw new ApiException("邮箱已存在请使用其他邮箱注册");
        }
        // 加密密码
        String salt = MD5Utils.getSalt();
        String encodePwd = MD5Utils.md5(user.getPassword(), salt);

        // 构建用户数据
        User newUser = new User(user.getUsername(),encodePwd, salt, user.getEmail());
        int insert = userMapper.insert(newUser);
        if (insert != 1) {
            throw new ApiException("注册失败");
        }
    }

    /**
     * 判读是否到重发时限
     *
     * @param codeKey 验证码key
     * @return true--重发，false--不重发
     */
    private Boolean checkRepeatSend(String codeKey, BaseMailConfig mailConfig) {
        Boolean hasKey = redisTemplate.hasKey(codeKey);
        if (hasKey == null || !hasKey) {
            return true;
        }
        Long expires = redisTemplate.getExpire(codeKey);
        if (expires != null) {
            // 发送验证码之后的时间超过（大于） 重发时限，则true
            log.info(mailConfig.getTimeout() - expires + "");
            return mailConfig.getTimeout() - expires > mailConfig.getRepeat();
        }
        return true;
    }

    /**
     * 登陆
     */
    @Override
    public LoginVo login(UserLoginParam userParam) {
        // 非微信登陆
        if (userParam.getEmail() == null || userParam.getPassword() == null) {
            throw new ApiException("邮箱或密码不能为空");
        }
        String email = userParam.getEmail();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("email", email);
        User user = userMapper.selectOne(wrapper);
        if (user == null) {
            throw new ApiException("用户不存在");
        }
        String pwd = MD5Utils.md5(userParam.getPassword(), user.getSalt());
        if (!pwd.equals(user.getPassword())) {
            throw new ApiException("密码错误");
        }

        // 在用户登录后在redis中设置语种
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(tokenUtils.grantToken( user.getUserId(), Roles.ROLE_USER));
        loginVo.setLan(statisticsService.getLan(user.getUserId().intValue()));
        return loginVo;
    }

    @Override
    public UserInfoVo getUserInfo(Long uid) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("user_id", uid);
//        userQueryWrapper.select("username", "avatar", "email","gmt_create");
        User user = userMapper.selectOne(userQueryWrapper);

        return new UserInfoVo(user);
    }

    @Override
    public void editUser(Long uid, User editUserParam) {
//        if (editUserParam.getUsername() == null && editUserParam.getAvatar() == null) {
//            throw new ApiException("参数错误");
//        }
        User copy = BeanCopyUtils.copy(editUserParam, User.class);
        copy.setUserId(uid);
        userMapper.updateById(copy);
    }

    // 退出登陆
    @Override
    public void logout(Long uid) {
        tokenUtils.safeExit(uid);
    }

    @Override
    public void editPassword(long uid, EditPasswordParam editPasswordParam) {
        User user = userMapper.selectById(uid);
        if (user == null) {
            throw new ApiException("用户不存在");
        }
        // 判断旧密码是否匹配
        if (!MD5Utils.md5(editPasswordParam.getOldPassword(), user.getSalt()).equals(user.getPassword())) {
            throw new ApiException("原密码错误");
        }

        User user1 = new User();
        user1.setUserId(uid);
        // 设置新盐值
        user1.setSalt(MD5Utils.getSalt());
        // 设置新密码
        user1.setPassword(MD5Utils.md5(editPasswordParam.getNewPassword(), user1.getSalt()));
        // 更新密码
        userMapper.updateById(user1);
    }
}




